﻿// E-Book Copier
// Copyright (C) 2009 Chuan-Gen Fan
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Project: http://code.google.com/p/ebookcopier/
// Contact Author:
//    website: http://chuangen.name/
// e-mail/msn: chuangen@live.cn

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Windows.Forms;

namespace EbookCopier
{
    /// <summary>
    /// 对将一组图片装订成 PDF 文档功能的封装。
    /// </summary>
    public partial class PdfCreator
    {
        static Font font = null;
        /// <summary>
        /// 页眉/页脚的字体。
        /// </summary>
        static Font headerFont
        {
            get
            {
                if (font == null)
                {
                    string fontsPath = SpecialFolders.Fonts;
                    ////黑体
                    //BaseFont bfHei = BaseFont.CreateFont(Path.Combine(fontsPath, "SIMHEI.TTF"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                    //宋体
                    BaseFont bfSun0 = BaseFont.CreateFont(Path.Combine(fontsPath, "SIMSUN.TTC,0"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                    ////新宋体
                    //BaseFont bfSun1 = BaseFont.CreateFont(Path.Combine(fontsPath, "SIMSUN.TTC,1"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

                    font = new Font(bfSun0, 12, Font.BOLD);
                    //footerFont = new Font(bfSun0, 12);
                }

                return font;
            }
        }
        /// <summary>
        /// 提供在后台生成 PDF 文档的能力。
        /// </summary>
        BackgroundWorker bw = null;
        System.Windows.Forms.Form owner = null;
        /// <summary>
        /// 初始化类 <see cref="PdfCreator"/> 的新实例。
        /// </summary>
        /// <param name="owner">父窗体</param>
        public PdfCreator(System.Windows.Forms.Form owner)
        {
            this.owner = owner;

            bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;

            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {//取消
                System.Windows.Forms.MessageBox.Show(owner.TopLevelControl, "生成操作已被用户取消。", "提示");
                processForm.Hide();
            }
            else if (e.Error != null)
            {//出错
                System.Windows.Forms.MessageBox.Show(owner.TopLevelControl, "生成过程中发生错误。\r\n\r\n" + e.Error.Message, "提示");
                processForm.Hide();
            }
            else
            {//成功创建 PDF 文档。
                processForm.Hide();
                string filename = e.Result as string;
                //打开保存的目录
                if (File.Exists(filename))
                {
                    try
                    {
                        System.Diagnostics.Process.Start(filename);
                    }
                    catch (Exception)
                    { }
                }
            }
        }
        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = sender as BackgroundWorker;

            object[] args = e.Argument as object[];
            if (args == null || args.Length < 3)
                return;

            string filename = args[0] as string;
            PdfSettings settings = args[1] as PdfSettings;
            IList<string> imagefiles = args[2] as IList<string>;
            CreatePdf(bw, e, filename, settings, imagefiles);
        }

        PdfProcessForm processForm = null;
        /// <summary>
        /// 启动异步生成 PDF。
        /// </summary>
        /// <param name="filename">PDF 文档路径</param>
        /// <param name="settings">PDF 文档设置</param>
        /// <param name="imagefiles">要添加的图片文件路径集合。</param>
        /// <returns></returns>
        public bool StartCreatePdfAsync(string filename, PdfSettings settings, IList<string> imagefiles)
        {
            if (bw.IsBusy)
                return false;

            if (processForm == null || processForm.IsDisposed)
            {
                processForm = new PdfProcessForm(bw);
                processForm.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
                processForm.ProgressPercentage = 0;
            }
            if (processForm.Visible)
                processForm.Activate();
            else
                processForm.Show(owner.TopLevelControl);

            object[] args = new object[] { filename, settings, imagefiles };
            bw.RunWorkerAsync(args);

            return true;
        }

        /// <summary>
        /// 解析 页码页脚。将“{P}”替换为页码。
        /// </summary>
        /// <param name="contents">页眉/页脚 的格式化文本内容。</param>
        /// <returns>HeaderFooter 实例。</returns>
        static HeaderFooter ParseHeaderFooter(string contents)
        {
            //页眉或页脚中包含 {P} 则为页码。
            string pageMark = "{P}";

            HeaderFooter footer = null;
            int index = contents.IndexOf(pageMark);
            if (index >= 0)
            {//有页码
                string before = contents.Substring(0, index);
                int afterLength = contents.Length - index - pageMark.Length;
                if (afterLength > 0)
                {//有尾部
                    string after = contents.Substring(index + pageMark.Length, afterLength);
                    footer = new HeaderFooter(new Phrase(before, headerFont), new Phrase(after, headerFont));
                }
                else
                {//没尾部
                    footer = new HeaderFooter(new Phrase(before, headerFont), true);
                }
            }
            else
            {//没有页码
                footer = new HeaderFooter(new Phrase(contents, headerFont), false);
            }
            footer.Alignment = HeaderFooter.ALIGN_CENTER;
            footer.Border = Rectangle.NO_BORDER;

            return footer;
        }
        /// <summary>
        /// 在 DoWork 中执行生成 PDF 文档的过程。
        /// </summary>
        static void CreatePdf(BackgroundWorker bw, DoWorkEventArgs e, string filename, PdfSettings settings, IList<string> imagefiles)
        {
            try
            {
                // step 1: creation of a document-object
                Document document = new Document();

                bw.ReportProgress(5);
                // step 2:
                // we create a writer that listens to the document
                // and directs a PDF-stream to a file
                PdfWriter.GetInstance(document, new FileStream(filename, FileMode.Create));

                // step 3: we open the document
                document.Open();//new Uri("")

                document.AddTitle(settings.Title);
                document.AddAuthor(settings.Author);
                document.AddSubject(settings.Subject);
                document.AddKeywords(settings.Keywords);
                document.AddCreator("电子书籍复印机 (http://chuangen.name)");

                if (settings.Header != null && settings.Header.Trim() != "")
                {//添加页眉
                    document.Header = ParseHeaderFooter(settings.Header);
                }
                if (settings.Footer != null && settings.Footer.Trim() != "")
                {
                    document.Footer = ParseHeaderFooter(settings.Footer);
                }

                document.SetMargins(settings.LeftMargin,
                    settings.RightMargin,
                    settings.TopMargin,
                    settings.BottomMargin);

                bw.ReportProgress(10);

                int finished = 0;
                foreach (string file in imagefiles)
                {
                    if (bw.CancellationPending)//已经取消
                    {
                        e.Cancel = true;
                        e.Result = null;
                        return;
                    }

                    System.Drawing.Image iamge = System.Drawing.Image.FromFile(file);
                    Image pdfImage = Image.GetInstance(iamge, System.Drawing.Imaging.ImageFormat.Png);
                    //Image.GetInstance("harbour.wmf")
                    pdfImage.Alignment = Image.MIDDLE_ALIGN;
                    pdfImage.ScaleToFit(document.Right - document.Left - document.LeftMargin - document.RightMargin,
                        document.Top - document.Bottom - document.TopMargin - document.Bottom);
                    document.Add(pdfImage);

                    finished++;
                    bw.ReportProgress(10 + 80 * finished / imagefiles.Count);
                }

                // step 5: we close the document
                document.Close();
                bw.ReportProgress(100);
                e.Result = filename;
            }
            catch (DocumentException ex)
            {//重设错误信息。
                throw new Exception("PDF 文档操作过程中出现错误，" + ex.Message, ex);
            }
            catch (IOException ex)
            {
                throw new Exception("PDF 文档操作过程中出现读写错误，" + ex.Message, ex);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// 启动 PDF 文档生成的用户界面。
        /// </summary>
        /// <param name="title">PDF 文档的标题。</param>
        /// <param name="imagefiles">要添加的图片文件路径集合。</param>
        public void CreatePDF(string title, IList<string> imagefiles)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "选择 PDF 文档保存路径";
            sfd.Filter = "PDF 文档(*.pdf)|*.pdf|所有文件(*.*)|*.*";
            if (title != null && title.Trim() != "")
                sfd.FileName = title + ".pdf";

            if (sfd.ShowDialog(owner.TopLevelControl) == DialogResult.OK)
            {
                string filename = sfd.FileName;

                PdfSettings pdfSet = new PdfSettings();
                if (title != null && title.Trim() != "")
                {
                    pdfSet.Title = title;
                    pdfSet.Header = title;
                }

                PdfSetForm setForm = new PdfSetForm(pdfSet);
                setForm.StartPosition = FormStartPosition.CenterScreen;
                if (setForm.ShowDialog(owner.TopLevelControl) == DialogResult.OK)
                {
                    this.StartCreatePdfAsync(filename, pdfSet, imagefiles);
                }
            }
        }

    }
}
